home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / foogol < prev    next >
Encoding:
Internet Message Format  |  1987-03-01  |  19.6 KB

  1. Subject:  v08i088:  A (vax) compiler for a tiny ALGOL-like language
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: seismo!enea!suadb!lindberg (Per Lindberg QZ)
  6. Mod.sources: Volume 8, Issue 88
  7. Archive-name: foogol
  8.  
  9. [  You'll have to write your own RTS, and link it in.  See the
  10.    documentation... --r$  ]
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line,
  14. # then unpack it by saving it in a file and typing "sh file".
  15. # If all goes well, you will see the message "End of shell archive."
  16. # Contents:  Makefile foogol.doc foogol.c
  17. # Wrapped by rs@mirror
  18. PATH=/bin:/usr/bin:/usr/ucb; export PATH
  19. echo shar: extracting "'Makefile'" '(53 characters)'
  20. if test -f 'Makefile' ; then 
  21.   echo shar: will not over-write existing file "'Makefile'"
  22. else
  23. sed 's/^X//' >Makefile <<'@//E*O*F Makefile//'
  24. Xfoogol:    foogol.c
  25. X    $(CC) $(CFLAGS) -o foogol foogol.c
  26. @//E*O*F Makefile//
  27. if test 53 -ne "`wc -c <'Makefile'`"; then
  28.     echo shar: error transmitting "'Makefile'" '(should have been 53 characters)'
  29. fi
  30. fi # end of overwriting check
  31. echo shar: extracting "'foogol.doc'" '(4379 characters)'
  32. if test -f 'foogol.doc' ; then 
  33.   echo shar: will not over-write existing file "'foogol.doc'"
  34. else
  35. sed 's/^X//' >foogol.doc <<'@//E*O*F foogol.doc//'
  36. Xfc.doc                        Last modified: 1986-12-15
  37. X
  38. X
  39. X            The FOOGOL-IV compiler
  40. X           relese notes and documentation
  41. X               Per Lindberg, QZ
  42. X                  The mad programmer strikes again!
  43. X
  44. XNAME
  45. X    fc - foogol compiler
  46. X
  47. XSYNOPSIS
  48. X    fc [ -d ] infile [ outfile ]
  49. X
  50. XDESCRIPTION
  51. X    fc compiles a foogol program into VAX/UNIX assembly language.
  52. X    Default extentions are ".foo" for the source file and ".s"
  53. X    for the compiled file. In other words, the resulting outfile
  54. X    is is VAX/UNIX assembly language, and can be assebled and
  55. X    linked with the vanilla UNIX as and ld programs.
  56. X
  57. X    Options: (There is only one switch so far...)
  58. X
  59. X    -d    Sets the debug option, which makes the compiler print
  60. X        out internal diagnostics. Useful for debugging and
  61. X        understanding the compiler.
  62. X
  63. X    The foogol object code has to be linked with the RTS (Run-Time
  64. X    system) and the C library in order to be able to do I/O.
  65. X    Example:
  66. X        fc foo
  67. X        as foo.s -o foo.o
  68. X        ld /lib/crt0.o rts.o foo.o -o foo -lc
  69. X    Or (shorter):
  70. X        fc foo
  71. X        cc rts.o foo.s -o foo
  72. X
  73. X    The RTS (Run-Time System) should be compiled before it is
  74. X    linked with the foogol object code. It consists of just three
  75. X    output functions written in C:
  76. X
  77. X    PRS(s) char *s; { printf("%s",s); }
  78. X
  79. X    PRN(i) int i;   { printf("%d",i); }
  80. X
  81. X    PR()            { putchar('\n');  }
  82. X
  83. X    The foogol language is basically a very small ALGOL. The
  84. X    current syntactic elements are:
  85. X
  86. X    PROGRAM ::=        begin
  87. X                [ DECLARATION ; ]
  88. X                STATEMENT [ ; STATEMENT ]...
  89. X                end
  90. X
  91. X    DECLARATION    ::=    integer ID_SEQUENCE
  92. X
  93. X    ID_SEQUENCE    ::=    IDENTIFIER [ , IDENTIFIER ]
  94. X
  95. X    STATEMENT    ::=    IO_STATEMENT
  96. X            !    WHILE_STATEMENT
  97. X            !    COND_STATEMENT
  98. X            !    BLOCK
  99. X            !    ASSIGN_STATEMENT
  100. X
  101. X    BLOCK        ::=        begin
  102. X                [ DECLARATION ]
  103. X                [ ; STATEMENT ]...
  104. X                end
  105. X
  106. X    IO_STATEMENT    ::=    prints ( STRING )
  107. X            !    printn ( EXPRESSION )
  108. X            !    print
  109. X
  110. X    COND_STATEMENT    ::=    if EXPRESSION then STATEMENT
  111. X                [ else STATEMENT ]
  112. X
  113. X    WHILE_STATEMENT    ::=    while EXPRESSION do STATEMENT
  114. X
  115. X    ASSIGN_STATEMENT::=    IDENTIFIER := EXPRESSION
  116. X
  117. X    EXPRESSION    ::=    EXPR1 [ RHS ]
  118. X
  119. X    RHS        ::=    = EXPR1
  120. X            !    # EXPR1
  121. X
  122. X    SIGNED_TERM    ::=    + TERM
  123. X            !    - TERM
  124. X
  125. X    TERM        ::=    PRIMARY [ * PRIMARY ]...
  126. X
  127. X    PRIMARY        ::=    IDENTIFIER
  128. X            !    NUMBER
  129. X            !    ( EXPRESSION )
  130. X
  131. X    EXPR1        ::=    TERM [ SIGNED_TERM ]...
  132. X
  133. X    IDENTIFIER    ::=    <the usual thing, and no word reserved>
  134. X
  135. X    NUMBER        ::=    <the usual thing, unsigned integers>
  136. X
  137. X    STRING        ::=    <the usual thing>
  138. X
  139. X    Example program:
  140. X
  141. X    begin
  142. X      integer n, div, sub, test, testcopy, found, max;
  143. X      test := 2; max := 10; /* number of primes wanted */
  144. X      while n # max do begin
  145. X        div:= test-1; found:= 0;
  146. X        while div-1 do begin
  147. X          testcopy:= test; sub:= 0;
  148. X          while testcopy do begin
  149. X            sub:= sub+1; if sub = div then sub:= 0;
  150. X            testcopy:= testcopy-1
  151. X          end;
  152. X          if sub = 0 then found:= 1;
  153. X          div:= div-1
  154. X        end;
  155. X        if found = 0 then begin
  156. X          n:= n+1;
  157. X          printn(test); prints(" is prime number "); printn(n); print
  158. X        end;
  159. X        test:= test+1
  160. X      end
  161. X    end
  162. X
  163. X    The syntax is highly flexible, which means it might easily be
  164. X    changed due to some whim. The source code should be checked
  165. X    for details and changes before bugs are reported.
  166. X
  167. X    The compiler is written by Per Lindberg, and placed in the
  168. X    public domain. The Hacker's Ethic applies. It is based on the
  169. X    VALGOL I compiler published by G.A. Edgar in Dr. Dobb's
  170. X    Journal May 1985. It was implemented for the purpouse of
  171. X    demonstrating how a simple compiler works. Therefore, there
  172. X    are no optimizations or other frills. You might want to add
  173. X    things to it; go right ahead. Happy hacking!
  174. X
  175. XFILES
  176. X    fc.c    Source code for the foogol compiler
  177. X    fc    The foogol compiler
  178. X    rts.c    Source code for the Run-Time system
  179. X    rts.o    The Run-Time system
  180. X    fc.doc    This file
  181. X    bar.foo    Your program...
  182. X
  183. XSEE ALSO
  184. X    as, ld, cc
  185. X
  186. XBUGS
  187. X    There are no scoping rules, all declared variables can be used
  188. X    throughout the entire program. And although you can have local
  189. X    declarations in blocks, these declarations are in fact global.
  190. X    So you can't redeclare a variable.
  191. X
  192. X    Because parsing is by simple recursive-descent and backtracking,
  193. X    there is only one cheerful error message: "Syntax error". No
  194. X    hints on missing or superflous semicolons or such hand-holding.
  195. X    You're supposed to write correct programs in foogol, Buster!
  196. X
  197. X    The output code is extremely naive, and very suitable for
  198. X    code optimization exercises.
  199. X
  200. X    Finally, please remember that this is just a 500-line toy
  201. X    compiler, so don't expect too much of it.
  202. @//E*O*F foogol.doc//
  203. if test 4379 -ne "`wc -c <'foogol.doc'`"; then
  204.     echo shar: error transmitting "'foogol.doc'" '(should have been 4379 characters)'
  205. fi
  206. fi # end of overwriting check
  207. echo shar: extracting "'foogol.c'" '(13095 characters)'
  208. if test -f 'foogol.c' ; then 
  209.   echo shar: will not over-write existing file "'foogol.c'"
  210. else
  211. sed 's/^X//' >foogol.c <<'@//E*O*F foogol.c//'
  212. X/*---------------------------------------------------------------------*\
  213. X!                                                                       !
  214. X!  fc.c  Compiler for FOOGOL IV -- version 4.2  Last change:1985-12-02  !
  215. X!        Translates FOOGOL IV into VAX/UNIX assembler                   !
  216. X!                                                                       !
  217. X!    Written by Per Lindberg, QZ, Box 27322, 10254 Stockholm, Sweden.   !
  218. X!                                                                       !
  219. X!    This software is in the public domain. The Hacker Ethic applies.   !
  220. X!    (A postcard from anyone who ports it would be appreciated.)        !
  221. X!                                                                       !
  222. X\*---------------------------------the-mad-programmer-strikes-again----*/
  223. X
  224. X#define UNIX
  225. X
  226. X#ifdef SARG10            /* Sargasso C (under TOPS10/20) peculiarities */
  227. X  #strings low
  228. X  #define _UNIXCON
  229. X#endif
  230. X
  231. X#include <stdio.h>
  232. X
  233. X#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
  234. X#define tolower(c) ((c) - 'A' + 'a')
  235. X
  236. X#define MAXTAB     25           /* Tweak these to your own liking  */
  237. X#define MAXTOKEN   80
  238. X
  239. X#define WHITESPACE  0           /* These could be turned into enum */
  240. X#define NUMBER      1
  241. X#define LETTER      2
  242. X#define QUOTE       3
  243. X#define SEMICOLON   4
  244. X#define RANDOM      5
  245. X
  246. XFILE *inf, *outf;
  247. X
  248. Xint labelcount = 0,
  249. X    linecount  = 0,
  250. X    debug      = 0;
  251. X
  252. Xchar token[MAXTOKEN],
  253. X     pending[MAXTOKEN],
  254. X     keytab[MAXTAB][MAXTOKEN],
  255. X     symtab[MAXTAB][MAXTOKEN],
  256. X     *usage =
  257. X#ifdef SARG10
  258. X     "usage: '.run fc- [-debug] infile [outfile]'";
  259. X#endif
  260. X#ifdef UNIX
  261. X     "usage: 'fc [-debug] infile [outfile]'";
  262. X#endif
  263. X
  264. Xmain(argc,argv) int argc; char *argv[]; {
  265. X  if (argc < 2) error(usage);
  266. X  if (*argv[1] == '-') { debug = 1; --argc; ++argv; }
  267. X  if (argc < 2) error(usage);
  268. X  openinfile(argv[1]);
  269. X  openoutfile(argv[argc == 2 ? 1 : 2]);
  270. X  init();
  271. X  if (!PROGRAM()) error("Syntax error");
  272. X  fclose(inf);
  273. X  fclose(outf);
  274. X}
  275. X
  276. Xchar *defaultext(fname,ext,force) char *fname, *ext; int force; {
  277. X  static char result[255];
  278. X  char c, *point, *s = result;
  279. X  strcpy(result,fname);
  280. X  while (*s) ++s;
  281. X  point = s;
  282. X  while (c = *s, s > result && c != '.') --s;
  283. X  if (c == '.') {                                /* some extention exists */
  284. X    point = s;
  285. X    if (!force) return result;            /* don't worry about what it is */
  286. X  }
  287. X  strcpy(point,ext);                 /* put default extention after point */
  288. X  return result;
  289. X}
  290. X
  291. Xopeninfile(fname) char *fname; {
  292. X  char *defaultext();
  293. X  d("openinfile",defaultext(fname,".foo",0),"");
  294. X  if ((inf = fopen(defaultext(fname,".foo",0),"r")) == NULL)
  295. X    error2("Can't open infile", defaultext(fname,".foo",0));
  296. X}
  297. X
  298. Xopenoutfile(fname) char *fname; {
  299. X  char *defaultext();
  300. X  d("openoutfile",defaultext(fname,".s",1),"");
  301. X  if ((outf = fopen(defaultext(fname,".s",1),"w")) == NULL)
  302. X    error2("Can't open outfile", defaultext(fname,".s",1));
  303. X}
  304. X
  305. Xinit() {
  306. X  int i;
  307. X  d("init","","");
  308. X  get2();
  309. X  gettoken();
  310. X  for (i = 0; i < MAXTAB; i++) keytab[i][0] = '\0';
  311. X}
  312. X
  313. Xerror(msg) char *msg; {
  314. X  printf("\n\nFoo: %s", msg);
  315. X  if (linecount) printf(" at line %d",linecount + 1);
  316. X  printf("\n");
  317. X  exit(1);
  318. X}
  319. X
  320. Xerror2(s1,s2) char *s1,*s2; {
  321. X  static char msg[80];
  322. X  sprintf(msg,"%s\"%s\"",s1,s2);
  323. X  error(msg);
  324. X}
  325. X
  326. Xlowcase(s) char *s; {
  327. X  char c;
  328. X  for (c = *s; c = *s; ++s) if (isupper(c)) *s = tolower(c);
  329. X}
  330. X
  331. X/* Basic I/O functions */
  332. X
  333. Xint out(line) char *line; {
  334. X  char c, symb[MAXTOKEN], *subst(), *s = symb;
  335. X  int printmode = 1, chmode = 1;
  336. X  while(c = *line++) {
  337. X    if (c == ' ') { if (chmode) putc('\t',outf);
  338. X                    chmode = 0;
  339. X    } else {
  340. X      chmode = 1;
  341. X      if (c != 39) { if (printmode) putc(c,outf);
  342. X                     else           *s++ = c;
  343. X      } else if (!printmode) {
  344. X             *s = '\0';
  345. X             if (*symb) fprintf(outf,"%s",subst(symb));
  346. X             printmode = 1;
  347. X           } else {
  348. X             printmode = 0;
  349. X             s = symb;
  350. X           }
  351. X    }
  352. X  }
  353. X  putc('\n',outf);
  354. X  return 1;
  355. X}
  356. X
  357. Xgettoken() {
  358. X  strcpy(token,pending); get2();
  359. X  if (!strcmp("/",token) && !strcmp("*",pending)) {
  360. X    d("comment:",token,pending);
  361. X    while (strcmp("*",token) || strcmp("/",pending)) {
  362. X      strcpy(token,pending); get2();
  363. X      d("        ",token,"");
  364. X    }
  365. X    strcpy(token,pending); get2();
  366. X    strcpy(token,pending); get2();
  367. X  }
  368. Xd("gettoken returning",token,pending);
  369. X}
  370. X
  371. Xget2() {
  372. X  int c0, c, typ, count = 1;
  373. X  char *p = pending;
  374. X  while((typ=type(c0=getc(inf))) == WHITESPACE) if (c0 == '\n') ++linecount;
  375. X  if (c0 != EOF) *p++ = c0;
  376. X  if (typ == QUOTE) {
  377. X    while ((c = getc(inf)) != EOF && type(c) != QUOTE) {
  378. X      if (++count == MAXTOKEN) error("String too long");
  379. X      *p++ = c;
  380. X    }
  381. X    *p++ = '"';
  382. X  }
  383. X  else {
  384. X    while ((type(c=getc(inf)) == typ
  385. X            || typ == LETTER && type(c) == NUMBER)
  386. X        && typ != RANDOM
  387. X            && c != EOF) {
  388. X      *p++ = c;
  389. X      typ = type(c);
  390. X      if (++count == MAXTOKEN) error("Too long input token");
  391. X    }
  392. X    ungetc(c,inf);
  393. X  }
  394. X  *p = '\0';  
  395. X}
  396. X
  397. Xint type(c) int c; {
  398. X  if (c == EOF) return -1;
  399. X  if (c >= '0' && c <= '9') return(NUMBER);
  400. X  if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') return(LETTER);
  401. X  if (c == ' ' || c == '\t' || c == '\n') return(WHITESPACE); /*  */
  402. X  if (c == '"') return (QUOTE);
  403. X  if (c == ';') return (SEMICOLON);
  404. X  return(RANDOM);
  405. X}
  406. X
  407. X/* Basic input matching functions */
  408. X
  409. Xint match(s) char *s; {
  410. Xd("match",token,s);
  411. X  lowcase(token);
  412. X  if (strcmp(s,token)) return 0;
  413. X  gettoken();          return 1;
  414. X}
  415. X
  416. Xint id(name) char *name; {
  417. X  int t;
  418. X  char c, *p = token;
  419. X  d("id",token,name);
  420. X  if (type(*p++) != LETTER) return 0;
  421. X  while (c = *p++) {
  422. X    t = type(c);
  423. X    if (t != NUMBER && t != LETTER) return(0);
  424. X  }
  425. X  lowcase(token);
  426. X  enter(name,token);
  427. X  gettoken();
  428. X  return(1);
  429. X}
  430. X
  431. Xint number(name) char *name; {
  432. X  char c, *p = token;
  433. X  d("number",token,name);
  434. X  while (c = *p++) if (type(c) != NUMBER) return(0);
  435. X  enter(name,token);
  436. X  gettoken();
  437. X  return(1);
  438. X}
  439. X
  440. Xint string(name) char *name; {
  441. X  d("string",token,name);
  442. X  if (*token != '"') return 0;
  443. X  enter(name,token);
  444. X  gettoken();
  445. X  return 1;
  446. X}
  447. X
  448. Xlabel(name) char *name; {
  449. X  char result[6];
  450. X  d("label ",name,"");
  451. X  sprintf(result,"L%d",labelcount++);
  452. X  enter(name,result);
  453. X}
  454. X
  455. X/* Internal symbol table */
  456. X
  457. Xenter(key,val) char *key, *val; {
  458. X  int i;
  459. X  d("enter ",val,key);
  460. X  for (i = 0; i < MAXTAB; i++) {
  461. X    if (keytab[i][0] == '\0') {
  462. X      strcpy(keytab[i],key);
  463. X      strcpy(symtab[i],val);
  464. X      return;
  465. X    }
  466. X  }
  467. X  error2("INTERNAL SYMTAB ENTER ERROR, can't enter ", val);
  468. X}
  469. X
  470. Xint lookup(key) char *key; {
  471. X  int i;
  472. X  for (i = MAXTAB-1; i >= 0 ; i--) {
  473. X    if (!strcmp(key,keytab[i])) {
  474. X      d("lookup ",symtab[i],key);
  475. X      return i;
  476. X    }
  477. X  }
  478. X  error2("INTERNAL SYMTAB LOOKUP ERROR, can't find ", key);
  479. X}
  480. X
  481. Xchar *subst(key) char *key; {
  482. X  return symtab[lookup(key)];
  483. X}
  484. X
  485. Xremove(key) char *key; {
  486. X  keytab[lookup(key)][0] = '\0';
  487. X}
  488. X
  489. X/* Syntax definition. This is the neat part! */
  490. X
  491. Xint PROGRAM() { d("PROGRAM",token,pending);
  492. X  if (!match("begin"))    return 0;    out("      .text # # begin");
  493. X                    out("      .align 1");
  494. X                    out("      .globl  _main");
  495. X                    out("_main:");
  496. X                    out("      .word 0");
  497. X  if (!OPT_DECLARATION()) return 0;
  498. X  if (!STATEMENT())    return 0;
  499. X  while (match(";"))
  500. X    if (!STATEMENT())    return 0;
  501. X  if (!match("end"))    return 0;    out("      ret   # # end");
  502. X  return 1;
  503. X}
  504. X
  505. Xint OPT_DECLARATION() { d("OPT_DECLARATION",token,pending);
  506. X  if (DECLARATION()
  507. X  && !match(";")) return 0;
  508. X  return 1;
  509. X}
  510. X
  511. Xint DECLARATION() { d("DECLARATION",token,pending);
  512. X  if (!match("integer")) return 0;    out("     .data  1 # integer");
  513. X  if (!ID_SEQUENCE())     return 0;    out("     .text");
  514. X  return 1;
  515. X}
  516. X
  517. Xint ID_SEQUENCE() { d("ID_SEQUENCE",token,pending);
  518. X  if (!IDENTIFIER())    return 0;
  519. X  while (match(","))
  520. X    if (!IDENTIFIER())    return 0;
  521. X  return 1;
  522. X}
  523. X
  524. Xint IDENTIFIER() { d("IDENTIFIER",token,pending);
  525. X  if (!id("X"))    return 0;        out("'X':  .long   0");
  526. X                    remove("X");
  527. X  return 1;
  528. X}
  529. X
  530. Xint STATEMENT() { d("STATEMENT",token,pending);
  531. X  return
  532. X  IO_STATEMENT()
  533. X  ||
  534. X  WHILE_STATEMENT()
  535. X  ||
  536. X  COND_STATEMENT()
  537. X  ||
  538. X  BLOCK()
  539. X  ||                     /* the order is important here */
  540. X  ASSIGN_STATEMENT();
  541. X}
  542. X
  543. Xint BLOCK() { d("BLOCK",token,pending);
  544. X  if (!match("begin"))    return 0;    out(" # # # begin");
  545. X  if (DECL_OR_ST())
  546. X    while(match(";"))
  547. X     if (!STATEMENT())    return 0;
  548. X  if (!match("end"))    return 0;    out(" # # # end");
  549. X  return 1;
  550. X}
  551. X
  552. Xint DECL_OR_ST() { d("DECL_OR_ST",token,pending);
  553. X  return
  554. X  DECLARATION()
  555. X  ||
  556. X  STATEMENT();
  557. X}
  558. X
  559. Xint IO_STATEMENT() { d("IO_STATEMENT",token,pending);
  560. X  return
  561. X  PRINTS_STATEMENT()
  562. X  ||
  563. X  PRINTN_STATEMENT()
  564. X  ||
  565. X  PRINT_STATEMENT();
  566. X}
  567. X
  568. Xint PRINTS_STATEMENT() { d("PRINTS_STATEMENT",token,pending);
  569. X  if (!match("prints")) return 0;
  570. X  if (!match("("))    return 0;
  571. X  if (!string("S"))    return 0;    label("Ls");
  572. X                    out("      .data 1 # prints");
  573. X                    out("'Ls': .asciz  'S'");
  574. X                    out("      .text");
  575. X                    out("      pushal   'Ls'");
  576. X                    out("      calls   $1,_PRS");
  577. X                    remove("S"); remove("Ls");
  578. X  if (!match(")"))    return 0;
  579. X  return 1;
  580. X}
  581. X
  582. Xint PRINTN_STATEMENT() { d("PRINTN_STATEMENT",token,pending);
  583. X  if (!match("printn")) return 0;
  584. X  if (!match("("))    return 0;
  585. X  if (!EXPRESSION())    return 0;    out("      pushl  r0 # printn");
  586. X                    out("      calls   $1,_PRN");
  587. X  if (!match(")"))    return 0;
  588. X  return 1;
  589. X}
  590. X
  591. Xint PRINT_STATEMENT() { d("PRINT_STATEMENT",token,pending);
  592. X  if (!match("print"))    return 0;    out("      calls   $0,_PR # print");
  593. X  return 1;
  594. X}
  595. X
  596. Xint COND_STATEMENT() { d("COND_STATEMENT",token,pending);
  597. X  if (!match("if"))    return 0;    label("Lt"); label("Le"); label("Lq");
  598. X  if (!EXPRESSION())    return 0;    out("      tstl  r0 # if");
  599. X  if (!match("then"))    return 0;    out("      bneq  'Lq' # then");
  600. X                    out("      jmp   'Le'");
  601. X                    out("'Lq':");
  602. X  if (!STATEMENT())    return 0;    out("      jmp   'Lt'");
  603. X                    out("'Le': #     # # else");
  604. X  if (match("else"))
  605. X    if (!STATEMENT())    return 0;    out("'Lt': #     # # endif");
  606. X                    remove("Lt");remove("Le");remove("Lq");
  607. X  return 1;
  608. X}
  609. X
  610. Xint WHILE_STATEMENT() { d("WHILE_STATEMENT",token,pending);
  611. X  if (!match("while"))    return 0;    label("Lw"); label("Lx"); label("Lv");
  612. X                    out("'Lw': #     # # while");
  613. X  if (!EXPRESSION())    return 0;    out("      tstl  r0");
  614. X  if (!match("do"))    return 0;    out("      bneq  'Lv'");
  615. X                                        out("      jmp   'Lx'");
  616. X                                        out("'Lv': #     # # do");
  617. X  if(!STATEMENT())    return 0;    out("      jmp   'Lw'");
  618. X                    out("'Lx': #     # # endwhile");
  619. X                    remove("Lw");remove("Lx");remove("Lv");
  620. X  return 1;
  621. X}
  622. X
  623. Xint ASSIGN_STATEMENT() { d("ASSIGN_STATEMENT",token,pending);
  624. X  if (!id("Var"))    return 0;
  625. X  if (!match(":"))    return 0;
  626. X  if (!match("="))    return 0;
  627. X  if (!EXPRESSION())    return 0;    out("    movl  r0,'Var' # 'Var':=");
  628. X                    remove("Var");
  629. X  return 1;
  630. X}
  631. X
  632. Xint EXPRESSION() { d("EXPRESSION",token,pending);
  633. X  if (!EXPR1())        return 0;
  634. X  if (!OPT_RHS())    return 0;
  635. X  return 1;
  636. X}
  637. X
  638. Xint OPT_RHS() { d("OPT_RHS",token,pending);
  639. X  return
  640. X  RHS_EQ()
  641. X  ||
  642. X  RHS_NEQ()
  643. X  ||
  644. X  1;
  645. X}
  646. X
  647. Xint RHS_EQ() { d("RHS_EQ",token,pending);
  648. X  if (!match("="))    return 0;    label("L="); label("Ly");
  649. X                    out("      pushl  r0 # =");
  650. X  if (!EXPR1())        return 0;    out("      cmpl   (sp)+,r0");
  651. X                    out("      beql   'L='");
  652. X                    out("      movl   $0,r0");
  653. X                    out("      jmp    'Ly'");
  654. X                    out("'L=': movl   $1,r0");
  655. X                    out("'Ly':");
  656. X                    remove("L="); remove("Ly");
  657. X  return 1;
  658. X}
  659. X
  660. Xint RHS_NEQ() { d("RHS_NEQ",token,pending);
  661. X  if (!match("#"))    return 0;    label("L#"); label("Lz");
  662. X                    out("      pushl  r0 # <>");
  663. X  if (!EXPR1())        return 0;    out("      cmpl   (sp)+,r0");
  664. X                    out("      beql   'L#'");
  665. X                    out("      movl   $1,r0");
  666. X                    out("      jmp    'Lz'");
  667. X                    out("'L#': movl   $0,r0");
  668. X                    out("'Lz':");
  669. X                    remove("L#"); remove("Lz");
  670. X  return 1;
  671. X}
  672. X
  673. Xint SIGNED_TERM() { d("SIGNED_TERM",token,pending);
  674. X  return
  675. X  PLUS_TERM()
  676. X  ||
  677. X  MINUS_TERM();
  678. X}
  679. X
  680. Xint PLUS_TERM() { d("PLUS_TERM",token,pending);
  681. X  if (!match("+"))    return 0;    out("      pushl  r0   # +term");
  682. X  if (!TERM())        return 0;    out("      addl2  (sp)+,r0");
  683. X  return 1;
  684. X}
  685. X
  686. Xint MINUS_TERM() { d("MINUS_TERM",token,pending);
  687. X  if (!match("-"))    return 0;    out("      pushl  r0   # -term");
  688. X  if (!TERM())        return 0;    out("      subl3  r0,(sp)+,r0");
  689. X  return 1;
  690. X}
  691. X
  692. Xint TERM() { d("TERM",token,pending);
  693. X  if (!PRIMARY())    return 0;
  694. X  while (match("*")) {            out("      pushl  r0    # *");
  695. X    if (!PRIMARY())    return 0;    out("      mull2  (sp)+,r0");
  696. X  }
  697. X  return 1;
  698. X}
  699. X
  700. Xint PRIMARY() { d("PRIMARY",token,pending);
  701. X  if (id("Z")) {            out("       movl 'Z',r0");
  702. X                    remove("Z");
  703. X    return 1;
  704. X  }
  705. X  if (number("Z")) {            out("       movl $'Z',r0");
  706. X                    remove("Z");
  707. X    return 1;
  708. X  }
  709. X  if (match("(")) {
  710. X    if (!EXPRESSION())    return 0;
  711. X    if (!match(")"))    return 0;
  712. X    return 1;
  713. X  }
  714. X  return 0;
  715. X}
  716. X
  717. Xint EXPR1() { d("EXPR1",token,pending);
  718. X  if (!TERM())        return 0;
  719. X  while(SIGNED_TERM());
  720. X  return 1;
  721. X}
  722. X
  723. X/* And finally, the debug function... */
  724. X
  725. Xint d(s1,s2,s3) char *s1,*s2,*s3; {
  726. X  if (debug) {
  727. X    printf("%s",s1);
  728. X    if (*s2) printf(" \"%s\"",s2);
  729. X    if (*s3) printf(" \"%s\"",s3);
  730. X    putchar('\n');
  731. X  }
  732. X  return 1;
  733. X}
  734. @//E*O*F foogol.c//
  735. if test 13095 -ne "`wc -c <'foogol.c'`"; then
  736.     echo shar: error transmitting "'foogol.c'" '(should have been 13095 characters)'
  737. fi
  738. fi # end of overwriting check
  739. echo shar: "End of shell archive."
  740. exit 0
  741.